home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / usenet / volume5 / crypto < prev    next >
Encoding:
Text File  |  1988-09-21  |  49.8 KB  |  1,847 lines

  1. Path: uunet!tektronix!tekgen!tekred!games
  2. From: games@tekred.TEK.COM
  3. Newsgroups: comp.sources.games
  4. Subject: v05i066:  crypto - the cryptogram puzzler's friend
  5. Message-ID: <3061@tekred.TEK.COM>
  6. Date: 21 Sep 88 18:49:16 GMT
  7. Sender: billr@tekred.TEK.COM
  8. Reply-To: davison@drivax.UUCP (Wayne Davison)
  9. Lines: 1835
  10. Approved: billr@saab.CNA.TEK.COM
  11.  
  12. Submitted by: davison@drivax.UUCP (Wayne Davison)
  13. Comp.sources.games: Volume 5, Issue 66
  14. Archive-name: crypto
  15.  
  16.     [This is a neat program! I compiled and ran it on a Sun with
  17.      no problems. Looks like it will work on SysV with a minor edit
  18.      to the Makefile.    -br]
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  README Makefile crypto.c crypto.man puzzles
  28. # Wrapped by billr@saab on Wed Sep 21 11:49:01 1988
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'README' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'README'\"
  32. else
  33. echo shar: Extracting \"'README'\" \(1528 characters\)
  34. sed "s/^X//" >'README' <<'END_OF_FILE'
  35. XCrypto.c is my contribution to the world of cryptogram puzzle solvers.  I wrote
  36. Xit a few months ago to encode and solve fortunes, and to decode the cryptograms
  37. Xfound in _Games_ magazine.  Included is an example multi-puzzle file which will
  38. Xlet you try out the program.  After compilation, type "crypto puzzles" and type
  39. Xa "?" for a brief summary of commands.  Consult the manpage for more info.
  40. X
  41. XThe program is written using curses, and as such is (hopefully) quite portable.
  42. XEdit the Makefile if the curses library link is not "-lcurses -ltermcap", or if
  43. Xyour system uses strrchr() rather than rindex().
  44. X
  45. XCrypto helps those who enjoy solving cryptograms by:
  46. X    o    Encoding regular text
  47. X    o    Using pre-encoded files which may or may not include the solution
  48. X    o    Interactivley placing letters into the puzzle
  49. X    o    Non-interactivley encoding/decoding puzzle text
  50. X    o    Searching /usr/dict/words for possible matches of a particular word
  51. X    o    Creating/accessing multi-puzzle files
  52. X
  53. XFor example, execute the command:
  54. X
  55. X    fortune | crypto -e >>puzz
  56. X
  57. Xten times, then the command:
  58. X
  59. X    crypto puzz
  60. X
  61. Xto solve all ten puzzles at your leisure.  You can switch from puzzle to
  62. Xpuzzle, and save the current state of any one or all ten puzzles.  You can
  63. Xeven cheat by having the program correct one (or more) letters in the puzzle.
  64. X--
  65. X Wayne Davison                          ...amdahl!drivax!davison
  66. X=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  67. X   bcd'f bf g hif ij jkd fi cihlm fnmcm fompmdqikchr aidqmojkh sortfiuogpc?
  68. X
  69. END_OF_FILE
  70. if test 1528 -ne `wc -c <'README'`; then
  71.     echo shar: \"'README'\" unpacked with wrong size!
  72. fi
  73. # end of 'README'
  74. fi
  75. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  76.   echo shar: Will not clobber existing file \"'Makefile'\"
  77. else
  78. echo shar: Extracting \"'Makefile'\" \(201 characters\)
  79. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  80. X##
  81. X##    Simple Makefile:
  82. X##
  83. X
  84. X##  Edit appropriately.
  85. XLIBS    = -lcurses -ltermcap
  86. X##  Choose one:
  87. XCFLAGS    = -O
  88. X## or
  89. X#CFLAGS    = -O -Drindex=strrchr
  90. X
  91. Xcrypto:        crypto.c
  92. X    cc $(CFLAGS) crypto.c -o crypto $(LIBS)
  93. END_OF_FILE
  94. if test 201 -ne `wc -c <'Makefile'`; then
  95.     echo shar: \"'Makefile'\" unpacked with wrong size!
  96. fi
  97. # end of 'Makefile'
  98. fi
  99. if test -f 'crypto.c' -a "${1}" != "-c" ; then 
  100.   echo shar: Will not clobber existing file \"'crypto.c'\"
  101. else
  102. echo shar: Extracting \"'crypto.c'\" \(36106 characters\)
  103. sed "s/^X//" >'crypto.c' <<'END_OF_FILE'
  104. X#include <stdio.h>
  105. X#include <curses.h>
  106. X#include <signal.h>
  107. X
  108. X#define    COLS    80
  109. X#define    ROWS    (24-2)
  110. X
  111. X#define INIT_GUESS    1
  112. X#define INIT_CYPHER    2
  113. X
  114. X#define DRAW_CRYPT_MSGS    0
  115. X#define DRAW_CRYPT    1
  116. X#define DRAW_MSGS    2
  117. X#define DRAW_HINT_ON    3
  118. X#define DRAW_HINT_OFF    4
  119. X
  120. X#define BUFF_SIZE    8176
  121. X#define PUZZLE_MAX    (ROWS-2)
  122. X
  123. Xchar *buffer, *buff_cp, *buff_titles;        /* main buffer pointers */
  124. Xchar *cypher, *guess, *used;            /* puzzle-specific pointers */
  125. Xchar *cl_cypher, *cl_guess;            /* pointers into command-line */
  126. Xchar string[90], string2[40];            /* general purpose strings */
  127. X
  128. Xstruct {                    /* the multi-puzzle structure */
  129. X    char *title, *ptr;
  130. X    int  length;
  131. X    char solved, changed;
  132. X    int  voffset, hoffset;
  133. X    int  maxrow, maxcol;
  134. X    char *hint_cp, *hint_end;
  135. X} puzzle[PUZZLE_MAX], *puzz;
  136. X
  137. Xint  puz_count = -1, puz_number, spacing;
  138. X
  139. Xchar *status_msg = NULL;
  140. Xchar *myname, *mytty, *ttyname();
  141. X
  142. X
  143. Xint  cypher_flag = 0, draw_mode = DRAW_CRYPT_MSGS;
  144. Xchar upper_flag  = 0, use_stdin = 1, braces = 1, encrypt_flag = 0;
  145. Xchar toggle_flag = 0, easy_flag = 0, init_flag = 0;
  146. X
  147. X
  148. X#define ISPUNCT(ch)    ((ch) < 'A' || (ch) > 'z' || ((ch) > 'Z' && (ch) < 'a'))
  149. X#define ISUPPER(ch)    ((ch) <= 'Z' && (ch) >= 'A')
  150. X#define ISLOWER(ch)    ((ch) >= 'a' && (ch) <= 'z')
  151. X#define TOUPPER(ch)    (ISLOWER(ch)? (ch)-('a'-'A') : (ch))
  152. X#define TOLOWER(ch)    (ISUPPER(ch)? (ch)+('a'-'A') : (ch))
  153. X
  154. Xlong random();
  155. Xvoid wrap_it_up();
  156. Xchar *malloc(), *rindex();
  157. X
  158. Xvoid main( argc, argv )
  159. Xint  argc;
  160. Xchar *argv[];
  161. X{
  162. X    int  i, j;
  163. X    int  ch, ch2;
  164. X
  165. X    /*
  166. X    || Remember who we are.
  167. X    */
  168. X    if( (myname = rindex( *argv, '/' )) == NULL ) {
  169. X    myname = *argv;
  170. X    } else {
  171. X    ++myname;
  172. X    }
  173. X    /*
  174. X    || Check arg count.  If no args, tell them about us.
  175. X    */
  176. X    if( argc == 1 ) {
  177. X    fprintf( stderr, "usage: %s [-cegnru] [file(s)]\n", myname );
  178. X    fprintf( stderr, "help:  %s -h,  %s -i\n", myname, myname );
  179. X    exit( 1 );
  180. X    }
  181. X
  182. X    /*
  183. X    || Try to grab enough memory to hold a few good cryptograms.
  184. X    */
  185. X    if( (buffer = malloc( BUFF_SIZE )) == NULL ) {
  186. X    fprintf( stderr, "Sorry -- not enough memory.\n" );
  187. X    exit( 2 );
  188. X    }
  189. X    buff_cp     = buffer;
  190. X    buff_titles = buffer + BUFF_SIZE;
  191. X
  192. X    srandom( time(0) );            /* bump the randomizer off-track */
  193. X
  194. X    /*
  195. X    || Parse the entire command tail.  Options must appear first.
  196. X    */
  197. X    while( --argc ) {
  198. X    if( **++argv == '-' ) {
  199. X        while( *++*argv ) {
  200. X        switch( TOLOWER(**argv) ) {
  201. X          case 'r':            /* rot-based encoding */
  202. X            if( (easy_flag = atoi( *argv+1 )) < 1 || easy_flag > 26 ) {
  203. X            easy_flag = -1;        /* enable random rot */
  204. X            }
  205. X            while( *++*argv <= '9' && **argv >= '0' ) {
  206. X            ;
  207. X            }
  208. X            *--*argv;
  209. X          case 'e':
  210. X            encrypt_flag = 1;        /* enable encryption */
  211. X            break;
  212. X          case 'u':
  213. X            upper_flag = 1;        /* set upper-case flag */
  214. X            break;
  215. X          case 'c':            /* grab user-specified code */
  216. X            cl_cypher = (*argv)+1;
  217. X            ch          = '?';
  218. X            i          = INIT_CYPHER;
  219. X            goto c_and_g;
  220. X          case 'g':            /* grab initial guess */
  221. X            cl_guess = (*argv)+1;
  222. X            ch         = '_';
  223. X            i         = INIT_GUESS;
  224. X          c_and_g:            /* cypher & guess init */
  225. X            if( init_flag & i ) {
  226. X            fprintf( stderr, "You specified too many -%c options.\n", **argv );
  227. X            exit( 1 );
  228. X            }
  229. X            init_flag |= i;
  230. X            if( strlen( *argv+1 ) != 26 ) {
  231. X            fprintf( stderr, "-%c option must be followed by exactly 26 characters.\n", **argv );
  232. X            exit( 1 );
  233. X            }
  234. X            for( i = 0; i < 26; ++i ) {
  235. X            ++*argv;
  236. X            if( ISPUNCT( **argv ) ) {
  237. X                **argv = ch;
  238. X            } else {
  239. X                **argv = TOLOWER( **argv );
  240. X            }
  241. X            }
  242. X            break;
  243. X          case 'n':
  244. X            braces = FALSE;
  245. X            break;
  246. X          case 'h':
  247. X            help1();        /* tell them about the command options */
  248. X            exit( 0 );
  249. X          case 'i':        /* tell them about our interactive mode */
  250. X            printf( "\nInteractive commands:\n" );
  251. X            help2();
  252. X            printf( " ?           Display this help message.\n" );
  253. X            exit( 0 );
  254. X          default:
  255. X            fprintf( stderr, "Uknown option:  \"%c\".\n", **argv );
  256. X            exit( 1 );
  257. X        }/* switch */
  258. X        }/* while */
  259. X    } else {            /* we found a non-option */
  260. X        use_stdin = FALSE;
  261. X        do {            /* process as many files as we find */
  262. X        if( freopen( *argv, "r", stdin ) ) {
  263. X            process_file();
  264. X        } else {
  265. X            fprintf( stderr, "Unable to open \"%s\" for input.\n", *argv );
  266. X        }
  267. X        ++argv;
  268. X        } while( --argc );
  269. X        break;
  270. X    }/* if */
  271. X    }/* while */
  272. X
  273. X    if( use_stdin ) {            /* if no files were specified, */
  274. X    process_file();            /* process stdin */
  275. X    }
  276. X    if( puz_count >= 0 ) {        /* finish last puzzle */
  277. X    puzzle_eof();        /* (might decrement puz_count if empty) */
  278. X    }
  279. X    if( puz_count < 0 ) {
  280. X    fprintf( stderr, "No puzzle text processed.\n" );
  281. X    exit( 2 );
  282. X    }
  283. X    if( buff_cp+2 >= buff_titles ) {
  284. X    fprintf( stderr, "Not enough room for entire puzzle file.\n" );
  285. X    }
  286. X
  287. X    /*
  288. X    || If we are going to operate interactivly, we need to get our ttyname
  289. X    || to re-instate the stdin to our tty.  At the same time, we check our
  290. X    || stdout, and set pipe mode if it is not a tty.
  291. X    */
  292. X    if( (mytty = ttyname( 1 )) == NULL ) {
  293. X    select_puzzle( 0 );
  294. X    if( !braces ) {                /* if no braces are output, */
  295. X        for( i = 0; i < 26; ++i ) {        /*output solution even if only */
  296. X        if( guess[i] != '_' ) {        /*a partial guess is present. */
  297. X            puzz->solved = TRUE;
  298. X            break;
  299. X        }
  300. X        }
  301. X    }
  302. X    save_cryptogram( stdout );
  303. X    exit( 0 );
  304. X    }
  305. X
  306. X    if( freopen( mytty, "r", stdin ) == NULL ) { /* get real tty input */
  307. X        fprintf( stderr, "Unable to open \"%s\".\n", mytty );
  308. X        exit( 2 );
  309. X    }
  310. X
  311. X    initscr();                     /* setup screen handling */
  312. X    savetty();
  313. X    noecho();
  314. X    raw();
  315. X
  316. X    signal( SIGINT, wrap_it_up );
  317. X    if( signal( SIGQUIT, SIG_IGN ) != SIG_IGN ) {
  318. X    signal( SIGQUIT, wrap_it_up );
  319. X    }
  320. X
  321. X    /*
  322. X    || Select the first (or only) puzzle to solve.
  323. X    */
  324. X    select_puzzle( 0 );            /* choose first puzzle */
  325. X    if( puz_count ) {            /* if multiple puzzles, prompt user */
  326. X    if( !puzzle_prompt() ) {
  327. X        wrap_it_up();
  328. X    }
  329. X    }
  330. X    clear();                /* clear the screen */
  331. X
  332. X    for( ;; ) {
  333. X    screen_update( draw_mode );    /* Update the screen */
  334. X    draw_mode = DRAW_MSGS;        /* assume message-update next time */
  335. X
  336. X    ch = getch();
  337. X    ch = TOLOWER(ch);
  338. X    switch( ch ) {
  339. X      case 'Q'-'@':                /* quit the program */
  340. X      case '['-'@':
  341. X      case EOF:
  342. X        if( !ok_to_exit() ) {        /* is it ok to exit? */
  343. X        ch = char_prompt( ROWS, 34, "Exit? (Y/N)? " );
  344. X        if( ch != 'y' && ch != EOF ) {
  345. X            break;
  346. X        }
  347. X        }
  348. X        wrap_it_up();            /* cleanup & exit */
  349. X        break;
  350. X      case 'U'-'@':                /* undo a guessed letter */
  351. X        ch = char_prompt( ROWS, 46, "Undo: " );
  352. X        if( ISLOWER(ch) ) {
  353. X        guess[ch-'a'] = '_';
  354. X        draw_mode = ch;
  355. X        puzz->changed = TRUE;
  356. X        } else {
  357. X        status_msg = "Invalid entry";
  358. X        }
  359. X        break;
  360. X      case 'X'-'@':                /* undo all guessed letters */
  361. X        for( i = 0; i < 26; ++i ) {
  362. X        guess[i] = '_';
  363. X        }
  364. X        draw_mode = DRAW_CRYPT_MSGS;
  365. X        puzz->changed = TRUE;
  366. X        break;
  367. X      case 'C'-'@':                /* they want to cheat! */
  368. X        if( !cypher_flag ) {
  369. X        status_msg = "Unable to cheat -- Sorry!";
  370. X        break;
  371. X        }
  372. X        status_msg = "That's all the cheating I know!";
  373. X        ch = (random() % 26);
  374. X        for( i = 0; i < 26; ++i ) {
  375. X        if( used[i] ) {
  376. X            for( j = 0; j < 26; ++j ) {
  377. X            if( cypher[j] == i+'a' ) {
  378. X                break;
  379. X            }
  380. X            }
  381. X            if( j < 26 && guess[i] != j+'a' ) {
  382. X            if( guess[i] == '_' ) {
  383. X                sprintf( status_msg = string2,
  384. X                "Cheating -- added %c --> %c.", i+'A', j+'A' );
  385. X            } else {
  386. X                sprintf( status_msg = string2,
  387. X                "Cheating -- changed %c --> %c (was %c).",
  388. X                 i+'A', j+'A', guess[i]-'a'+'A' );
  389. X            }
  390. X            guess[i] = j+'a';
  391. X            break;
  392. X            }
  393. X        } else {
  394. X            if( guess[i] != '_' ) {
  395. X            sprintf( status_msg = string2,
  396. X                "Cheating -- removed %c (was %c).",
  397. X                 i+'A', guess[i]-'a'+'A' );
  398. X            guess[i] = '_';
  399. X            break;
  400. X            }
  401. X        }
  402. X        ch = (ch + 1) % 26;
  403. X        }
  404. X        draw_mode = DRAW_CRYPT_MSGS;
  405. X        puzz->changed = TRUE;
  406. X        break;
  407. X      case 'H'-'@':                /* Hint (dictionary search) */
  408. X        hint();
  409. X        break;
  410. X      case 'D'-'@':                /* define solution */
  411. X        if( cypher_flag > 0 ) {
  412. X        status_msg = "I like my solution better.";
  413. X        break;
  414. X        }
  415. X        for( i = 0; i < 26; ++i ) {
  416. X        cypher[i] = '?';
  417. X        }
  418. X        for( i = 0; i < 26; ++i ) {
  419. X        if( guess[i] != '_' ) {
  420. X            cypher[guess[i]-'a'] = i+'a';
  421. X        }
  422. X        }
  423. X        cypher_flag = -1;
  424. X        status_msg = "Defined solution.";
  425. X        puzz->changed = TRUE;
  426. X        break;
  427. X      case 'S'-'@':                /* save current puzzle state */
  428. X        if( !save_file( ROWS, 34, FALSE ) ) {
  429. X        break;
  430. X        }
  431. X        if( puzz->solved ) {
  432. X        status_msg = "Saved solution.";
  433. X        } else {
  434. X        status_msg = "Saved puzzle.";
  435. X        }
  436. X        break;
  437. X      case 'T'-'@':            /* enter new title for cryptogram */
  438. X        move( ROWS, 0 );
  439. X        clrtobot();
  440. X        if( string_prompt( ROWS, 0, "Title: " ) ) {
  441. X        status_msg = "Aborted.";
  442. X        break;
  443. X        }
  444. X        draw_mode = DRAW_CRYPT_MSGS;
  445. X        if( !*string ) {
  446. X        if( puzz->title ) {
  447. X            --puzz->maxrow;
  448. X            puzz->title = NULL;
  449. X            puzz->changed = TRUE;
  450. X        }
  451. X        break;
  452. X        }
  453. X        if( (i = strlen( string )) > COLS-4 ) {
  454. X        i = COLS-4;
  455. X        string[i] = '\0';
  456. X        }
  457. X        if( (buff_titles -= i+1) < buff_cp ) {
  458. X        status_msg = "Not enough room.";
  459. X        buff_titles += i+1;
  460. X        break;
  461. X        }
  462. X        if( !puzz->title ) {
  463. X        ++puzz->maxrow;
  464. X        }
  465. X        strcpy( buff_titles, string );
  466. X        puzz->title = buff_titles;
  467. X        puzz->changed = TRUE;
  468. X        break;
  469. X      case 'A'-'@':            /* toggle alphabet display mode */
  470. X        toggle_flag = !toggle_flag;
  471. X        break;
  472. X      case 'N'-'@':            /* next puzzle (if multi-puzzled) */
  473. X        if( ++puz_number > puz_count ) {
  474. X        puz_number = 0;
  475. X        }
  476. X        select_puzzle( puz_number );
  477. X        draw_mode = DRAW_CRYPT_MSGS;
  478. X        break;
  479. X      case 'P'-'@':            /* previous puzzle (if multi-puzzled) */
  480. X        if( --puz_number < 0 ) {
  481. X        puz_number = puz_count;
  482. X        }
  483. X        select_puzzle( puz_number );
  484. X        draw_mode = DRAW_CRYPT_MSGS;
  485. X        break;
  486. X      case 'M'-'@':                /* display Menu of puzzles */
  487. X        if( !puzzle_prompt() ) {    /* check if they hit Esc */
  488. X        wrap_it_up();            /* cleanup & exit */
  489. X        }
  490. X        clear();
  491. X        draw_mode = DRAW_CRYPT_MSGS;
  492. X        break;
  493. X      case '?':            /* output command summary */
  494. X        clear();
  495. X        mvprintw( 0, 13, "%s -- a cryptogram solver,  By:  Wayne Davison\n",
  496. X                 myname );
  497. X        refresh();
  498. X        help2();
  499. X        mvaddstr( ROWS+1, 32, "[Press any key]" );
  500. X        refresh();
  501. X        getch();                /* (fall through) */
  502. X      case 'L'-'@':
  503. X      case 'R'-'@':
  504. X        clear();
  505. X        draw_mode = DRAW_CRYPT_MSGS;
  506. X        break;
  507. X      case '7':                /* goto left edge */
  508. X        puzz->hoffset = 0;
  509. X      case '4':                /* go left */
  510. X        if( (puzz->hoffset -= 4) <= 0 ) {
  511. X        puzz->hoffset = 0;
  512. X        status_msg = "[At left edge]";
  513. X        }
  514. X        draw_mode = DRAW_CRYPT_MSGS;
  515. X        break;
  516. X      case '1':                /* goto right edge */
  517. X        puzz->hoffset = 32760;
  518. X      case '6':                /* go right */
  519. X        if( (puzz->hoffset += 4) > puzz->maxcol-COLS ) {
  520. X        puzz->hoffset = puzz->maxcol-COLS;
  521. X        status_msg = "[At right edge]";
  522. X        }
  523. X        draw_mode = DRAW_CRYPT_MSGS;
  524. X        break;
  525. X      case '9':                /* goto top */
  526. X        puzz->voffset = 0;
  527. X      case '8':                /* go up */
  528. X        if( (puzz->voffset -= 2) <= 0 ) {
  529. X        puzz->voffset = 0;
  530. X        status_msg = "[At top]";
  531. X        }
  532. X        draw_mode = DRAW_CRYPT_MSGS;
  533. X        break;
  534. X      case '3':                /* goto bottom */
  535. X        puzz->voffset = 32760;
  536. X      case '2':                /* go down */
  537. X        if( (puzz->voffset += 2) >= puzz->maxrow-(ROWS/spacing) ) {
  538. X        puzz->voffset = puzz->maxrow-(ROWS/spacing);
  539. X        status_msg = "[At bottom]";
  540. X        }
  541. X        draw_mode = DRAW_CRYPT_MSGS;
  542. X        break;
  543. X      default:
  544. X        if( ISLOWER(ch) ) {        /* check for <let><let> substitution */
  545. X        addch( ch );
  546. X        refresh();
  547. X        ch2 = getch();
  548. X        ch2 = TOLOWER(ch2);
  549. X        if( ISLOWER(ch2) ) {
  550. X            guess[ch-'a'] = ch2;
  551. X            puzz->changed = TRUE;
  552. X        } else if( ch2 != '\010' && ch2 != '\177' ) {
  553. X            guess[ch-'a'] = '_';
  554. X            puzz->changed = TRUE;
  555. X        }
  556. X        draw_mode = ch;
  557. X        } else {
  558. X        status_msg = "Type '?' for help.";
  559. X        }
  560. X    }
  561. X    }/* forever */
  562. X}
  563. X
  564. Xint get_cypher( num )
  565. Xint num;
  566. X{
  567. X    int  i, j, k, n;
  568. X
  569. X    for( i = 0; i < 26; ++i ) {        /* create rotated cypher */
  570. X    cypher[i] = ( (i+num) % 26 )+'a';
  571. X    }
  572. X    if( num && !easy_flag ) {        /* if !easy, scramble it up */
  573. X    for( i = 0; i < 512; ++i ) {
  574. X        j = random() % 26;
  575. X        k = random() % 26;
  576. X        n = cypher[j];
  577. X        cypher[j] = cypher[k];
  578. X        cypher[k] = n;
  579. X    }
  580. X    }
  581. X}
  582. X
  583. Xprocess_file()
  584. X{
  585. X    char *cp, *line_start;
  586. X    int  i, new_puzzle;
  587. X    int  ch;
  588. X
  589. X    /*
  590. X    || Try to read in the file.  Encode (if applicable) as we read.
  591. X    */
  592. X    new_puzzle = TRUE;
  593. X
  594. X    while( buff_cp+2 < buff_titles && (ch = getchar()) != EOF ) {
  595. X    if( new_puzzle ) {
  596. X        new_puzzle = FALSE;
  597. X        if( buff_titles-buff_cp < 26*3+4 ) {
  598. X        fprintf( stderr, "Not enough room for all the puzzles.\n" );
  599. X        break;
  600. X        }
  601. X        if( puz_count == PUZZLE_MAX-1 ) {
  602. X        fprintf( stderr, "%d-puzzle maximum exceeded.\n", PUZZLE_MAX );
  603. X        break;
  604. X        }
  605. X        if( ++puz_count ) {        /* if previous puzzle, finish it up */
  606. X        puzzle_eof();
  607. X        }
  608. X
  609. X        puzz      = &puzzle[puz_count];
  610. X        puzz->ptr      = (buff_cp += 26*3);
  611. X        puzz->title   = NULL;
  612. X        puzz->maxrow  = puzz->maxcol  = 0;
  613. X        puzz->voffset = puzz->hoffset = 0;
  614. X
  615. X        line_start    = buff_cp;
  616. X        cypher    = buff_cp - 26;
  617. X        guess    = cypher  - 26;
  618. X        used    = guess   - 26;
  619. X
  620. X        /*
  621. X        || Setup the cypher's substitution array.  It is either:
  622. X        */
  623. X        if( (init_flag & INIT_CYPHER) ) {    /* a user-supplied cypher, */
  624. X        strcpy( cypher, cl_cypher );
  625. X        cypher_flag = -1;
  626. X        puzz->changed = TRUE;
  627. X        } else {
  628. X        if( encrypt_flag ) {        /* a randomly chosen cypher, */
  629. X            if( easy_flag <= 0 ) {
  630. X            get_cypher( (random() % 25)+1 );
  631. X            } else {
  632. X            get_cypher( easy_flag );
  633. X            }
  634. X            cypher_flag = 1;
  635. X            puzz->changed = TRUE;
  636. X        } else {
  637. X            get_cypher( 0 );        /* or none (1-to-1 mapping). */
  638. X            cypher_flag = 0;
  639. X            puzz->changed = use_stdin;
  640. X        }
  641. X        }
  642. X        /*
  643. X        || Initialize the guess array.  It is either:
  644. X        */
  645. X        for( i = 0; i < 26; ++i ) {
  646. X        if( init_flag & INIT_GUESS ) {
  647. X            guess[i] = cl_guess[i];    /* user-specified with -g, */
  648. X        } else {
  649. X            guess[i] = '_';        /* or initialized to all '_'s. */
  650. X        }
  651. X        used[i] = 0;            /* Also, set used to all 0's. */
  652. X        }
  653. X    }
  654. X    if( ch == '\n' ) {
  655. X        if( line_start[0] == '{' && *(buff_cp-1) == '}'
  656. X         && line_start[1] == '-' ) {
  657. X        if( (ch = line_start[2]) == 'c' || ch == 'g' ) {
  658. X            if( buff_cp-line_start != 30 ) {
  659. X            fprintf( stderr, "File has invalid {-%c...} entry.\n", ch );
  660. X            goto end_of_line;
  661. X            }
  662. X        }
  663. X        cp = &line_start[3];
  664. X
  665. X        switch( TOLOWER(ch) ) {
  666. X          case 'c':        /* found code specifier */
  667. X            for( i = 0; i < 26; ++i ) {
  668. X            if( !ISPUNCT(cp[i]) ) {
  669. X                cp[i] = cypher[TOLOWER(cp[i])-'a'];
  670. X            }
  671. X            }
  672. X            strncpy( cypher, cp, 26 );
  673. X            cypher_flag = 1;
  674. X            break;
  675. X          case 'g':        /* found guess specifier */
  676. X            if( init_flag & INIT_GUESS ) {
  677. X            fprintf( stderr, "Ignored file's -g entry.\n" );
  678. X            break;
  679. X            }
  680. X            for( i = 0; i < 26; ++i ) {
  681. X            if( ISPUNCT(cp[i]) ) {
  682. X                guess[i] = '_';
  683. X            } else {
  684. X                guess[i] = TOLOWER(cp[i]);
  685. X            }
  686. X            }
  687. X            break;
  688. X          case 'e':        /* found end of puzzle separator */
  689. X            new_puzzle = TRUE;
  690. X            break;
  691. X          case 't':        /* found title specifier */
  692. X            if( (i = strlen( cp )-1) > COLS-4 ) {
  693. X            i = COLS-4;
  694. X            }
  695. X            cp[i] = '\0';
  696. X            buff_titles -= i+1;
  697. X            if( line_start >= buff_titles ) {
  698. X            break;
  699. X            }
  700. X            puzz->title = buff_titles;
  701. X            ++puzz->maxrow;
  702. X            strcpy( buff_titles, cp );
  703. X            break;
  704. X          default:
  705. X            fprintf( stderr, "Unknown file option:  {-%c...}.\n", ch );
  706. X            goto end_of_line;
  707. X        }
  708. X        buff_cp = line_start;
  709. X        continue;
  710. X        }
  711. X    end_of_line:
  712. X        while( buff_cp > line_start && *(buff_cp-1) == ' ' ) {
  713. X        --buff_cp;        /* remove trailing spaces */
  714. X        }
  715. X        if( buff_cp == line_start
  716. X         && (buff_cp == puzz->ptr || *(buff_cp-2) == '\0') ) {
  717. X        continue;        /* skip leading/multiple blank lines */
  718. X        }
  719. X        ++puzz->maxrow;        /* remember maximum row/col numbers */
  720. X        if( buff_cp-line_start > puzz->maxcol ) {
  721. X        puzz->maxcol = buff_cp-line_start;
  722. X        }
  723. X        while( line_start < buff_cp ) {    /* encrypt & set used flag */
  724. X        if( !ISPUNCT(*line_start) ) {
  725. X            i = TOLOWER(*line_start)-'a';
  726. X            if( cypher[i] != '?' ) {
  727. X            used[cypher[i]-'a'] = 1;
  728. X            }
  729. X            if( upper_flag || ISUPPER(*line_start) ) {
  730. X            *line_start = TOUPPER(cypher[i]);
  731. X            } else {
  732. X            *line_start = cypher[i];
  733. X            }
  734. X        }
  735. X        ++line_start;
  736. X        }
  737. X        *buff_cp++ = '\0';
  738. X        line_start = buff_cp;
  739. X        continue;
  740. X    } else if( ch == '\010' && buff_cp != line_start ) {
  741. X        --buff_cp;                /* Backspace erases last char */
  742. X        continue;
  743. X    } else if( ch == '\t' ) {
  744. X        ch = ' ';                /* convert tabs to spaces */
  745. X        while( (buff_cp-line_start+1)%8 ) {
  746. X        *buff_cp++ = ' ';
  747. X        }
  748. X    }
  749. X    if( ch >= ' ' ) {
  750. X        *buff_cp++ = ch;            /* insert non-ctrl chars */
  751. X    }
  752. X    }
  753. X}
  754. X
  755. Xpuzzle_eof()                /* finish a puzzle's definition */
  756. X{
  757. X    int  i;
  758. X
  759. X    if( buff_cp == puzz->ptr ) {    /* forget puzzle if it is empty */
  760. X    buff_cp -= 26*3;
  761. X    --puz_count;
  762. X    return;
  763. X    }
  764. X    if( *(buff_cp-1) != '\0' ) {
  765. X    *buff_cp++ = '\0';        /* terminate last line if needed */
  766. X    } else if( *(buff_cp-2) == '\0' ) {
  767. X    --buff_cp;            /* remove any trailing blank line */
  768. X    --puzz->maxrow;
  769. X    }
  770. X    puzz->length = buff_cp - puzz->ptr;    /* remember length of puzzle */
  771. X    *buff_cp++ = '\177';
  772. X
  773. X    puzz->hint_cp = puzz->ptr;        /* setup the hint pointers */
  774. X    find_hint_word();
  775. X
  776. X    puzz->solved = FALSE;        /* set initial value of solved flag */
  777. X    if( cypher_flag ) {
  778. X    for( i = 0; i < 26; ++i ) {
  779. X        if( cypher[i] != '?'
  780. X         && (guess[cypher[i]-'a'] != '_' || used[cypher[i]-'a'])
  781. X         &&  guess[cypher[i]-'a'] != i+'a' ) {
  782. X        break;
  783. X        }
  784. X    }
  785. X    if( i == 26 ) {
  786. X        puzz->solved = TRUE;
  787. X    }
  788. X    }
  789. X}
  790. X
  791. Xint puzzle_prompt()        /* prompt user for puzzle selection */
  792. X{
  793. X    int  i, j, num;
  794. X
  795. X    j = (ROWS+2-puz_count)/2;    /* center the puzzle menu */
  796. X    clear();
  797. X    /*
  798. X    || Loop through all the puzzles, looking for titles to display.
  799. X    */
  800. X    for( i = 0; i <= puz_count; ++i ) {
  801. X    mvprintw( i+j, 0, "%2d. %s", i+1, puzzle[i].title? puzzle[i].title
  802. X                             : "<Untitled>" );
  803. X    }
  804. X    mvaddstr( i+j+1, 0, "<Press Esc to exit, ^S to save all the puzzles>" );
  805. X    /*
  806. X    || Ask the user which puzzle to start with.
  807. X    */
  808. X    for( ;; ) {
  809. X    move( j-1, 0 );
  810. X    clrtoeol();
  811. X    if( status_msg ) {
  812. X        mvaddstr( j-1, 34, status_msg );
  813. X        status_msg = NULL;
  814. X    }
  815. X    sprintf( string, "Which puzzle? (1 - %d)? ", puz_count+1 );
  816. X    if( (num = string_prompt( j-2, 0, string )) == 1 ) {
  817. X        if( !ok_to_exit() ) {
  818. X        num = char_prompt( j-2, 0, "Exit? (Y/N)? " );
  819. X        if( num != 'y' && num != EOF ) {
  820. X            continue;
  821. X        }
  822. X        }
  823. X        return( 0 );        /* if they want to exit, return 0 */
  824. X    }
  825. X    if( num == 2 ) {        /* handle saving of all puzzles */
  826. X        if( save_file( j-2, 0, TRUE ) ) {
  827. X        status_msg = "Saved all puzzles.";
  828. X        }
  829. X        continue;
  830. X    }
  831. X    if( !*string ) {    /* null string means return to last puzzle */
  832. X        return( 1 );
  833. X    }
  834. X    sscanf( string, "%d", &num );
  835. X    if( --num >= 0 && num <= puz_count ) {
  836. X        select_puzzle( num );    /* select new puzzle on valid number */
  837. X        return( 1 );
  838. X    }
  839. X    }
  840. X}
  841. X
  842. Xselect_puzzle( num )        /* setup the pointers for the current puzzle */
  843. Xint  num;
  844. X{
  845. X    int  i;
  846. X
  847. X    puz_number = num;
  848. X
  849. X    puzz   = &puzzle[puz_number];
  850. X    cypher = puzz->ptr - 26;
  851. X    guess  = cypher    - 26;
  852. X    used   = guess     - 26;
  853. X
  854. X    cypher_flag = 0;
  855. X    for( i = 0; i < 26; ++i ) {
  856. X    if( cypher[i] == '?' ) {
  857. X        cypher_flag = -1;
  858. X        break;
  859. X    }
  860. X    if( cypher[i] != i+'a' ) {
  861. X        cypher_flag = 1;
  862. X    }
  863. X    }
  864. X}
  865. X
  866. Xint save_file( row, col, multi_flag )    /* handle prompt & file saving */
  867. Xint row, col, multi_flag;
  868. X{
  869. X    FILE *fp;
  870. X    int  i, j;
  871. X    char ch;
  872. X
  873. X    /*
  874. X    || Prompt the user for save filename.
  875. X    */
  876. X    if( string_prompt( row, col, "Save file: " ) || !*string ) {
  877. X    status_msg = "Save aborted.";
  878. X    return( 0 );
  879. X    }
  880. X    if( (fp = fopen( string, "r" )) != NULL ) {    /* check for existing file */
  881. X    fclose( fp );
  882. X    ch = char_prompt( row+1, col, "Overwrite file? (Y/N): " );
  883. X    if( ch != 'y' ) {
  884. X        status_msg = "Save aborted.";
  885. X        return( 0 );
  886. X    }
  887. X    }
  888. X    if( (fp = fopen( string, "w" )) == NULL ) {    /* open a new file */
  889. X    status_msg = "Unable to create file.";
  890. X    return( 0 );
  891. X    }
  892. X    if( multi_flag ) {            /* if multi-puzzled, save them all */
  893. X    j = puz_number;
  894. X    for( i = 0; i <= puz_count; ++i ) {
  895. X        select_puzzle( i );
  896. X        save_cryptogram( fp );
  897. X    }
  898. X    select_puzzle( j );
  899. X    } else {
  900. X    save_cryptogram( fp );        /* else, save the current one */
  901. X    }
  902. X    fclose( fp );
  903. X
  904. X    return( 1 );
  905. X}
  906. X
  907. Xsave_cryptogram( fp )
  908. XFILE *fp;
  909. X{
  910. X    char *cp, ch;
  911. X    int  i;
  912. X
  913. X    if( braces && puzz->title ) {        /* output title if present */
  914. X    fprintf( fp, "{-t%s}\n", puzz->title );
  915. X    }
  916. X    if( !puzz->solved ) {    /* output cryptogram IF it's not all filled-in */
  917. X    for( cp = puzz->ptr; *cp != '\177'; ++cp ) {
  918. X        if( *cp ) {
  919. X        putc( *cp,  fp );
  920. X        } else {
  921. X        putc( '\n', fp );
  922. X        }
  923. X    }
  924. X    }
  925. X    if( braces ) {
  926. X    for( i = 0; i < 26; ++i ) {    /* check if they've guessed anything */
  927. X        if( guess[i] != '_' ) {
  928. X        break;
  929. X        }
  930. X    }
  931. X    if( i < 26 ) {
  932. X        fprintf( fp, "{-g%26.26s}\n", guess );/* output our current guess */
  933. X    }
  934. X    if( cypher_flag ) {              /* output code if known */
  935. X        fprintf( fp, "{-c%26.26s}\n", cypher );
  936. X    }
  937. X    }
  938. X    if( puzz->solved ) {        /* output solution if all filled-in */
  939. X    for( cp = puzz->ptr; *cp != '\177'; ++cp ) {
  940. X        if( *cp ) {
  941. X        if( !ISPUNCT(*cp) ) {
  942. X            ch = guess[TOLOWER(*cp)-'a'];
  943. X            if( ISUPPER(*cp) ) {
  944. X            ch = TOUPPER(ch);
  945. X            }
  946. X            putc( ch,  fp );
  947. X        } else {
  948. X            putc( *cp, fp );
  949. X        }
  950. X        } else {
  951. X        putc( '\n', fp );
  952. X        }
  953. X    }
  954. X    }
  955. X    if( braces ) {
  956. X    fprintf( fp, "{-end}\n" );        /* flag end of puzzle */
  957. X    }
  958. X    puzz->changed = FALSE;
  959. X}
  960. X
  961. Xint ok_to_exit()            /* check if any puzzles are changed */
  962. X{
  963. X    int  i;
  964. X
  965. X    for( i = 0; i <= puz_count; ++i ) {
  966. X    if( puzzle[i].changed ) {
  967. X        return( FALSE );
  968. X    }
  969. X    }
  970. X    return( TRUE );
  971. X}
  972. X
  973. Xint char_prompt( row, col, prompt )
  974. Xint  row, col;
  975. Xchar *prompt;
  976. X{
  977. X    int  ch;
  978. X
  979. X    mvaddstr( row, col, prompt );
  980. X    clrtoeol();
  981. X    refresh();
  982. X    ch = getch();
  983. X
  984. X    return( TOLOWER(ch) );
  985. X}
  986. X
  987. Xint string_prompt( row, col, prompt )
  988. Xint  row, col;
  989. Xchar *prompt;
  990. X{
  991. X    int  ch;
  992. X    char *cp;
  993. X
  994. X    mvaddstr( row, col, prompt );
  995. X    clrtoeol();
  996. X    refresh();
  997. X    cp = string;
  998. X    while( (ch = getch()) != '\r' ) {
  999. X    if( ch == '['-'@' || ch == 'C'-'@' || ch == EOF ) {
  1000. X        *string = '\0';
  1001. X        return( 1 );
  1002. X    }
  1003. X    if( ch == 'S'-'@' && col == 0 ) {
  1004. X        return( 2 );
  1005. X    }
  1006. X    if( (ch == 'H'-'@' || ch == '\177') && cp != string ) {
  1007. X        --cp;
  1008. X        ch = '\010';
  1009. X        addch( ch );
  1010. X        addch( ' ' );
  1011. X    } else if( ch >= ' ' && cp-string < 80 ) {
  1012. X        *cp++ = ch;
  1013. X    } else {
  1014. X        continue;
  1015. X    }
  1016. X    addch( ch );
  1017. X    refresh();
  1018. X    }
  1019. X    *cp = '\0';
  1020. X
  1021. X    return( 0 );
  1022. X}
  1023. X
  1024. Xscreen_update( draw_flag )
  1025. Xint draw_flag;
  1026. X{
  1027. X    char *cp, *s, guessed[26];
  1028. X    int  i, j, row, col;
  1029. X
  1030. X    if( draw_flag <= DRAW_CRYPT ) {
  1031. X    erase();
  1032. X    }
  1033. X    if( draw_flag != DRAW_MSGS ) {
  1034. X    /*
  1035. X    || First, skip any lines that are off the top of the screen.
  1036. X    */
  1037. X    i = (puzz->title == NULL)? 0 : 1;
  1038. X    for( cp = puzz->ptr; i < puzz->voffset && *cp != '\177'; ++i ) {
  1039. X        while( *cp++ ) {
  1040. X        ;
  1041. X        }
  1042. X    }
  1043. X    /*
  1044. X    || Now, loop for as many lines as will fit on a screen.
  1045. X    */
  1046. X    spacing = 2 + (puzz->maxrow*3 <= ROWS);
  1047. X
  1048. X    for( row = 0; row < ROWS && *cp != '\177'; row += spacing )
  1049. X    {
  1050. X        /*
  1051. X        || Output the title if present and visible.
  1052. X        */
  1053. X        if( row == 0 && puzz->voffset <= 0 && puzz->title ) {
  1054. X        mvprintw( row, 0, "%d. %s", puz_number+1, puzz->title );
  1055. X        continue;
  1056. X        }
  1057. X        /*
  1058. X        || Skip any text off the left side of the screen.
  1059. X        */
  1060. X        for( i = 0; i < puzz->hoffset && *cp; ++i, ++cp ) {
  1061. X        ;
  1062. X        }
  1063. X        /*
  1064. X        || Process each line as specified.
  1065. X        */
  1066. X        switch( draw_flag ) {
  1067. X          case DRAW_CRYPT:
  1068. X          case DRAW_CRYPT_MSGS:
  1069. X        move( row+1, 0 );
  1070. X        for( col = 0; *cp && col < COLS; ++cp, ++col ) {
  1071. X            if( ISPUNCT(*cp) ) {
  1072. X            addch( *cp );
  1073. X            } else {
  1074. X            j = guess[TOLOWER(*cp)-'a'];
  1075. X            if( ISUPPER(*cp) ) {
  1076. X                j = TOUPPER(j);
  1077. X            }
  1078. X            addch( j );
  1079. X            }
  1080. X        }
  1081. X        j = *cp;
  1082. X        *cp = '\0';
  1083. X        standout();
  1084. X        mvaddstr( row, 0, cp-col );
  1085. X        standend();
  1086. X        *cp = j;
  1087. X        break;
  1088. X          case DRAW_HINT_ON:
  1089. X          case DRAW_HINT_OFF:
  1090. X        for( col = 0; *cp && col < COLS; ++cp, ++col ) {
  1091. X            if( cp == puzz->hint_cp ) {
  1092. X            if( draw_flag == DRAW_HINT_ON ) {
  1093. X                standout();
  1094. X            }
  1095. X            move( row+1, col );
  1096. X            while( cp != puzz->hint_end ) {
  1097. X                if( (j = TOLOWER(*cp)) != '\'' ) {
  1098. X                j = guess[j-'a'];
  1099. X                if( ISUPPER(*cp) ) {
  1100. X                    j = TOUPPER(j);
  1101. X                }
  1102. X                }
  1103. X                addch( j );
  1104. X                ++cp;
  1105. X            }
  1106. X            standend();
  1107. X            row = ROWS;
  1108. X            break;
  1109. X            }
  1110. X        } /* for col */
  1111. X        break;
  1112. X          default:
  1113. X        for( col = 0; *cp && col < COLS; ++cp, ++col ) {
  1114. X            if( TOLOWER(*cp) == draw_flag ) {
  1115. X            move( row+1, col );
  1116. X            j = guess[TOLOWER(*cp)-'a'];
  1117. X            if( ISUPPER(*cp) ) {
  1118. X                j = TOUPPER(j);
  1119. X            }
  1120. X            addch( j );
  1121. X            }
  1122. X        }
  1123. X        }
  1124. X        /*
  1125. X        || Skip any text off the right side of the screen.
  1126. X        */
  1127. X        while( *cp++ ) {
  1128. X        ;
  1129. X        }
  1130. X    } /* for screenful */
  1131. X    } /* if */
  1132. X
  1133. X    switch( draw_flag ) {
  1134. X      case DRAW_HINT_ON:
  1135. X    /*
  1136. X    || Prompt for hint-word selection.
  1137. X    */
  1138. X    move( ROWS, 0 );
  1139. X    clrtobot();
  1140. X    if( status_msg ) {
  1141. X        mvaddstr( ROWS+1, 0, status_msg );
  1142. X        status_msg = NULL;
  1143. X    }
  1144. X    for( cp = puzz->hint_cp, s = string; cp < puzz->hint_end; ++cp ) {
  1145. X        if( (j = TOLOWER(*cp)) != '\'' ) {
  1146. X        j = guess[j-'a'];
  1147. X        }
  1148. X        *s++ = j;
  1149. X    }
  1150. X    *s = '\0';
  1151. X    standout();
  1152. X    mvprintw( ROWS,  0, "Look up \"%s\"?", string );
  1153. X    standend();
  1154. X    addch( ' ' );
  1155. X      case DRAW_HINT_OFF:
  1156. X      case DRAW_CRYPT:
  1157. X    break;
  1158. X      case DRAW_MSGS:
  1159. X      case DRAW_CRYPT_MSGS:
  1160. X      default:
  1161. X    /*
  1162. X    || Draw all messages, starting with the alphabet lines.
  1163. X    */
  1164. X    cp = string;
  1165. X    s  = string+35;
  1166. X    if( toggle_flag ) {
  1167. X        *cp++ = '/';
  1168. X        *s++  = '\\';
  1169. X        for( i = 0; i < 26; ++i ) {
  1170. X        if( used[i] || guess[i] != '_' ) {
  1171. X            *cp++ = i+'A';
  1172. X            *s++  = TOUPPER(guess[i]);
  1173. X        } else {
  1174. X            *cp++ = ' ';
  1175. X            *s++  = ' ';
  1176. X        }
  1177. X        }
  1178. X        *cp++ = '\\';
  1179. X        *s++  = '/';
  1180. X    } else {
  1181. X        for( i = 0; i < 26; ++i ) {
  1182. X        guessed[i] = 0;
  1183. X        for( j = 0; j < 26; ++j ) {
  1184. X            if( guess[j] == i+'a' ) {
  1185. X            *cp++ = j+'A';
  1186. X            *s++  = i+'A';
  1187. X            ++guessed[i];
  1188. X            }
  1189. X        }
  1190. X        }
  1191. X        *cp++ = ' ';
  1192. X        *s++  = ' ';
  1193. X        *cp++ = '[';
  1194. X        *s++  = '[';
  1195. X        for( i = 0; i < 26; ++i ) {
  1196. X        if( guess[i] == '_' && used[i] ) {
  1197. X            *cp++ = i+'A';
  1198. X        }
  1199. X        if( !guessed[i] ) {
  1200. X            *s++  = i+'A';
  1201. X        }
  1202. X        }
  1203. X        if( *(cp-1) != '[' ) {
  1204. X        j = ']';
  1205. X        } else {
  1206. X        j = ')';
  1207. X        *(cp-1) = '(';
  1208. X        }
  1209. X        if( *(s-1) != '[' ) {
  1210. X        *s++ = ']';
  1211. X        } else {
  1212. X        s -= 2;
  1213. X        }
  1214. X        for( i = 0; i < 26; ++i ) {
  1215. X        if( guess[i] == '_' && !used[i] ) {
  1216. X            *cp++ = i+'a';
  1217. X        }
  1218. X        }
  1219. X        if( *(cp-1) != '(' && *(cp-1) != '[' ) {
  1220. X        *cp++ = j;
  1221. X        } else {
  1222. X        cp -= 2;
  1223. X        }
  1224. X    }
  1225. X    *cp = '\0';
  1226. X    *s  = '\0';
  1227. X    standout();
  1228. X    mvaddstr( ROWS,   0, string+(*string==' ') );
  1229. X    standend();
  1230. X    clrtoeol();
  1231. X    mvaddstr( ROWS+1, 0, string+35+(*(string+35)==' ') );
  1232. X    clrtoeol();
  1233. X    /*
  1234. X    || Next, draw the status message if specified.
  1235. X    */
  1236. X    if( status_msg ) {
  1237. X        mvaddstr( ROWS+1, 39, status_msg );
  1238. X        status_msg = NULL;
  1239. X    }
  1240. X    /*
  1241. X    || Then, let them know if we like their solution.
  1242. X    */
  1243. X    standout();
  1244. X    if( cypher_flag ) {
  1245. X        for( i = 0; i < 26; ++i ) {
  1246. X        if( cypher[i] != '?'
  1247. X         && (guess[cypher[i]-'a'] != '_' || used[cypher[i]-'a'])
  1248. X         &&  guess[cypher[i]-'a'] != i+'a' ) {
  1249. X            break;
  1250. X        }
  1251. X        }
  1252. X        if( i == 26 ) {
  1253. X        puzz->solved = TRUE;
  1254. X        if( cypher_flag > 0 ) {
  1255. X            mvaddstr( ROWS, COLS-15, "You solved it!" );
  1256. X        } else {
  1257. X            mvaddstr( ROWS, COLS-15, "Looks good!" );
  1258. X        }
  1259. X        } else {
  1260. X        puzz->solved = FALSE;
  1261. X        }
  1262. X    }
  1263. X    /*
  1264. X    || Finally, prompt for a command.
  1265. X    */
  1266. X    mvaddstr( ROWS, 34, "Command:" );
  1267. X    standend();
  1268. X    addch( ' ' );
  1269. X    }
  1270. X    refresh();
  1271. X}
  1272. X
  1273. Xvoid wrap_it_up()
  1274. X{
  1275. X    clear();
  1276. X    refresh();
  1277. X    resetty();
  1278. X    endwin();
  1279. X
  1280. X    exit( 0 );
  1281. X}
  1282. X
  1283. Xhint()
  1284. X{
  1285. X    int  ch;
  1286. X
  1287. X    for( ;; ) {
  1288. X    screen_update( DRAW_HINT_ON );
  1289. X    ch = getch();
  1290. X    if( (ch = TOLOWER(ch)) == 'y' || ch == 'M'-'@' ) {
  1291. X        addch( 'Y' );
  1292. X        refresh();
  1293. X        match();
  1294. X        return;
  1295. X    }
  1296. X    screen_update( DRAW_HINT_OFF );
  1297. X    switch( ch ) {
  1298. X      case '6':            /* goto next word */
  1299. X      case ' ':
  1300. X      case 'n':
  1301. X        puzz->hint_cp = puzz->hint_end;
  1302. X        break;
  1303. X      case '8':            /* goto first word on previous line */
  1304. X        while( puzz->hint_cp != puzz->ptr && *--puzz->hint_cp ) {
  1305. X        ;
  1306. X        }
  1307. X        if( puzz->hint_cp == puzz->ptr ) {        /* wrap to eof */
  1308. X        puzz->hint_cp = puzz->ptr + puzz->length-1;
  1309. X        }
  1310. X        if( *(puzz->hint_cp-1) == '\0' ) {        /* skip double '\n' */
  1311. X        --puzz->hint_cp;
  1312. X        }
  1313. X      case '7':            /* goto first word of line */
  1314. X        while( puzz->hint_cp != puzz->ptr && *--puzz->hint_cp ) {
  1315. X        ;
  1316. X        }
  1317. X        break;
  1318. X      case '3':            /* goto last word of puzzle */
  1319. X        puzz->hint_cp = puzz->ptr + puzz->length;
  1320. X      case '1':            /* goto last word of line */
  1321. X      case '2':            /* goto first word of next line */
  1322. X        while( *puzz->hint_cp != '\177' && *puzz->hint_cp++ ) {
  1323. X        ;
  1324. X        }
  1325. X        if( ch == '2' ) {
  1326. X        break;
  1327. X        }
  1328. X      case '4':            /* goto previous word */
  1329. X        do {
  1330. X        if( puzz->hint_cp == puzz->ptr ) {
  1331. X            puzz->hint_cp += puzz->length;
  1332. X        }
  1333. X        --puzz->hint_cp;
  1334. X        } while( ISPUNCT(*puzz->hint_cp) );
  1335. X
  1336. X        while( puzz->hint_cp != puzz->ptr
  1337. X         && (*puzz->hint_cp == '\'' || !ISPUNCT(*puzz->hint_cp)) )
  1338. X        {
  1339. X        --puzz->hint_cp;
  1340. X        }
  1341. X        if( puzz->hint_cp != puzz->ptr ) {
  1342. X        ++puzz->hint_cp;
  1343. X        }
  1344. X        break;
  1345. X      case '9':            /* goto first word of puzzle */
  1346. X        puzz->hint_cp = puzz->ptr;
  1347. X        break;
  1348. X      case 'q':            /* quit hint mode */
  1349. X      case 'Q'-'@':
  1350. X      case '['-'@':
  1351. X        return;
  1352. X      case '?':            /* output help */
  1353. X        help3( 1 );
  1354. X        break;
  1355. X      default:            /* tell them about the help */
  1356. X        status_msg = "Type '?' for help.";
  1357. X        break;
  1358. X    }
  1359. X    find_hint_word();
  1360. X    } /* forever */
  1361. X}
  1362. X
  1363. Xfind_hint_word()
  1364. X{
  1365. X  find_it:
  1366. X    while( *puzz->hint_cp != '\177' && ISPUNCT(*puzz->hint_cp) ) {
  1367. X    ++puzz->hint_cp;
  1368. X    }
  1369. X    if( *puzz->hint_cp == '\177' ) {        /* wrap if at eof */
  1370. X    puzz->hint_cp = puzz->ptr;
  1371. X    goto find_it;
  1372. X    }
  1373. X    puzz->hint_end = puzz->hint_cp;
  1374. X    while( *puzz->hint_end == '\'' || !ISPUNCT(*puzz->hint_end) ) {
  1375. X    ++puzz->hint_end;
  1376. X    }
  1377. X}
  1378. X
  1379. Xmatch()
  1380. X{
  1381. X    FILE *fchan;
  1382. X    extern char *fgets();
  1383. X    char token[80], str[80], hguess[26];
  1384. X    register char *s, *t;
  1385. X    register int j, slen, tlen;
  1386. X
  1387. X    fchan = fopen( "/usr/dict/words", "r" );
  1388. X    if( !fchan ) {
  1389. X    status_msg = "Couldn't find dictionary!";
  1390. X    screen_update( DRAW_HINT_OFF );
  1391. X    return;
  1392. X    }
  1393. X    move( ROWS+1, 0 );
  1394. X    clrtoeol();
  1395. X    refresh();
  1396. X    slen = strlen(string);
  1397. X    while( fgets( token, (sizeof token), fchan ) ) {
  1398. X    if( *string != '_' ) {
  1399. X        if( TOLOWER(*token) < *string ) {
  1400. X        continue;
  1401. X        }
  1402. X        if( TOLOWER(*token) > *string ) {
  1403. X        break;
  1404. X        }
  1405. X    }
  1406. X    tlen = strlen(token);
  1407. X    token[--tlen] = '\0';
  1408. X    if( tlen != slen ) {
  1409. X        continue;
  1410. X    }
  1411. X    for( t = token; *t; ++t ) {
  1412. X        *t = TOLOWER(*t);
  1413. X        if( *t != '\'' && !ISLOWER(*t) ) {
  1414. X        goto nomatch;
  1415. X        }
  1416. X    }
  1417. X    strcpy( str, string );
  1418. X
  1419. X    for( j = 0; j < 26; ++j ) {
  1420. X        hguess[j] = 0;
  1421. X    }
  1422. X    for( j = 0; j < 26; ++j ) {
  1423. X        if( guess[j] != '_' ) {
  1424. X        hguess[guess[j]-'a'] = j + 'a';
  1425. X        }
  1426. X    }
  1427. X
  1428. X    for( s = str, t = token; *s; ++s, ++t) {
  1429. X        if( *s == *t ) {
  1430. X        continue;
  1431. X        } else if( *s != '_' || *t == '\'' || hguess[*t-'a'] ) {
  1432. X        goto nomatch;
  1433. X        } else {
  1434. X        j = s - str;
  1435. X        hguess[*t-'a'] = TOLOWER(puzz->hint_cp[j]);
  1436. X        for( ; j < slen; ++j ) {
  1437. X            if( TOLOWER(puzz->hint_cp[j]) == hguess[*t-'a'] ) {
  1438. X            str[j] = *t;
  1439. X            }
  1440. X        }
  1441. X        }
  1442. X    }
  1443. Xtryagain:
  1444. X    mvprintw( ROWS+1, 8, "\"%s\"? ", token );
  1445. X    refresh();
  1446. X    j = getch();
  1447. X    j = TOLOWER(j);
  1448. X    move( ROWS+1, 0 );
  1449. X    clrtoeol();
  1450. X    refresh();
  1451. X    switch( j ) {
  1452. X      case 'q':
  1453. X      case 'Q'-'@':
  1454. X      case '['-'@':
  1455. X        screen_update( DRAW_HINT_OFF );
  1456. X        goto noloop;
  1457. X      case 'y':
  1458. X      case 'M'-'@':
  1459. X        for( s = str, t = puzz->hint_cp; *s; ++s, ++t ) {
  1460. X        if( *t != '\'' ) {
  1461. X            guess[TOLOWER(*t)-'a'] = *s;
  1462. X        }
  1463. X        }
  1464. X        puzz->changed = TRUE;
  1465. X        screen_update( DRAW_CRYPT );
  1466. X        goto noloop;
  1467. X      case 'n':
  1468. X      case ' ':
  1469. X        break;
  1470. X      case '?':
  1471. X        help3( 0 );
  1472. X        screen_update( DRAW_HINT_ON );
  1473. X        addch( 'Y' );
  1474. X        refresh();
  1475. X        goto tryagain;
  1476. X      default:
  1477. X        mvaddstr( ROWS+1, 44, "Type '?' for help." );
  1478. X        goto tryagain;
  1479. X    }
  1480. Xnomatch: ;
  1481. X    }
  1482. X    status_msg = "No matches found.";
  1483. X    screen_update( DRAW_HINT_OFF );
  1484. X
  1485. Xnoloop:
  1486. X    fclose(fchan);
  1487. X}
  1488. X
  1489. Xhelp1()
  1490. X{
  1491. X    printf( "\nThis program allows you to interactively solve cryptogram puzzles, or to simply\n\r" );
  1492. X    printf( "filter the input to the standard output IF the output has been redirected.  The\n\r" );
  1493. X    printf( "input can be pre-encoded or I can encode it for you.  If I encode it, I will be\n\r" );
  1494. X    printf( "able to tell you when you have correctly solved the puzzle.\n\r\n" );
  1495. X    printf( "Command-line options:\n\r" );
  1496. X    printf( "\t-u\tforce all input to Upper-case.\n\r" );
  1497. X    printf( "\t-e\tEncode the input stream with a random cypher.\n\r" );
  1498. X    printf( "\t-r\tencode using a simpler, rot-based random cypher.  For a\n\r" );
  1499. X    printf( "\t\tspecific rotation, include a number from 1 to 26, e.g.:  -r13.\n\r" );
  1500. X    printf( "\t-cSTR\tencode using the Code STR as the encryption cypher.\n\r" );
  1501. X    printf( "\t-gSTR\tinitialize the Guessed letters to STR.\n\r" );
  1502. X    printf( "\t-n\tinclude No brace-commands when saving or piping.\n\r" );
  1503. X    printf( "\tFILE\tread input from one or more FILEs instead of stdin.\n\r" );
  1504. X    printf( "\t-i\toutput the Interactive commands.\n\r" );
  1505. X    printf( "\t-h\toutput this Help list.\n\r" );
  1506. X    printf( "\t-\tthe null option can be used to avoid an empty command tail.\n\r" );
  1507. X    printf( "\nExamples:\n\r" );
  1508. X    printf( "\tfortune -l | %s -r\n\r", myname );
  1509. X    printf( "\t%s -eu puzzles\n\r", myname );
  1510. X    printf( "\t%s -n -gzyxwvutsrqponmlkjihgfedcba code.file >result.file\n\r", myname );
  1511. X}
  1512. X
  1513. Xhelp2()
  1514. X{
  1515. X    printf( "\n\r<let1><let2> guess the substitution cypher a letter at a time.\n\r" );
  1516. X    printf( "<let><space> undefine <let>'s current guess.  <space> can be any non-letter.\n\r" );
  1517. X    printf( "^U<let>      the alternate way to Undefine a letter's current guess.\n\r" );
  1518. X    printf( "^X           Undefine ALL the guessed letters.\n\r" );
  1519. X    printf( "^H           Hint -- select a word to perform a dictionary search on.\n\r" );
  1520. X    printf( "^C           Cheat -- if I know the solution, I'll correct one letter.\n\r" );
  1521. X    printf( "^A           toggle the Alpha display between the two different output modes.\n\r" );
  1522. X    printf( "^T           enter a (new) Title for this puzzle.\n\r" );
  1523. X    printf( "^D           Define the current guess to be the solution. Useful before a save.\n\r" );
  1524. X    printf( "^S<file>     Save the current puzzle, guess, & cypher information in a file.\n\r" );
  1525. X    printf( "             Use the command:  %s <file>  to restore where you were.\n\r", myname );
  1526. X    printf( "^N           go to the Next puzzle when multiple puzzles are present.\n\r" );
  1527. X    printf( "^P           go to the Previous puzzle when multiple puzzles are present.\n\r" );
  1528. X    printf( "^M           choose a puzzle from a Menu when multiple puzzles are present.\n\r" );
  1529. X    printf( "^Q, <Esc>    Quit -- leave the program.\n\r" );
  1530. X    printf( "^L, ^R       Redraw the screen.\n\r" );
  1531. X    printf( " 6,  4       Move a wide cryptogram left/right by 4 chars.\n\r" );
  1532. X    printf( " 2,  8       Move a long cryptogram up/down by 2 lines.\n\r" );
  1533. X    printf( " 7,  1       Move to the far left/right of a wide puzzle.\n\r" );
  1534. X    printf( " 9,  3       Move to the top/bottom of a long puzzle.\n\r" );
  1535. X}
  1536. X
  1537. Xhelp3( flag )
  1538. Xint flag;
  1539. X{
  1540. X    clear();
  1541. X    if( flag ) {
  1542. X    mvaddstr( 1, 0, "Word selection commands:" );
  1543. X    } else {
  1544. X    mvaddstr( 1, 0, "Dictionary look-up commands:" );
  1545. X    }
  1546. X    refresh();
  1547. X    printf( "\n\r\n\rY, <Enter>   Yes:  accept the choice.\n\r" );
  1548. X    printf( "N, <Space>   No:   reject the choice.\n\r" );
  1549. X    printf( "Q, <Esc>     Quit: exit hint mode.\n\r" );
  1550. X    if( flag ) {
  1551. X    printf( "8, 2         Move up/down, line by line.\n\r" );
  1552. X    printf( "4, 6         Move left/right, word by word.\n\r" );
  1553. X    printf( "7, 1         Move to first/last word on the current line.\n\r" );
  1554. X    printf( "9, 3         Move to first/last line in cryptogram\n\r" );
  1555. X    }
  1556. X    printf( "?            Print this message.\n\r" );
  1557. X    mvaddstr( ROWS+1, 0, "[Press any key] " );
  1558. X    refresh();
  1559. X    getch();
  1560. X    clear();
  1561. X    screen_update( DRAW_CRYPT );
  1562. X}
  1563. END_OF_FILE
  1564. if test 36106 -ne `wc -c <'crypto.c'`; then
  1565.     echo shar: \"'crypto.c'\" unpacked with wrong size!
  1566. fi
  1567. # end of 'crypto.c'
  1568. fi
  1569. if test -f 'crypto.man' -a "${1}" != "-c" ; then 
  1570.   echo shar: Will not clobber existing file \"'crypto.man'\"
  1571. else
  1572. echo shar: Extracting \"'crypto.man'\" \(5709 characters\)
  1573. sed "s/^X//" >'crypto.man' <<'END_OF_FILE'
  1574. X.TH CRYPTO 1 LOCAL
  1575. X.SH NAME
  1576. Xcrypto \- a program to generate and/or solve cryptograms
  1577. X.SH SYNOPSIS
  1578. X.B crypto
  1579. X[-cegrsu] [file(s)]
  1580. X.SH DESCRIPTION
  1581. X.I Crypto
  1582. Xis a fun program for playing around with cryptograms. It can be used
  1583. Xto encode text with a random or user-picked cypher, to interactively solve
  1584. Xcryptogram puzzles, to non-interactively apply a solution to a text file,
  1585. Xand to save the results to the file of your choice.
  1586. X.PP
  1587. XIn normal usage, text is taken from the specified file (or
  1588. Xthe standard input), encoded (if needed) and displayed for 
  1589. Xyou to solve. You can save the current puzzle at any time,
  1590. Xand take up where you left off later on.  If the cypher is
  1591. Xpicked by (or supplied to)
  1592. X.I crypto\,
  1593. Xit will inform you when you have correctly solved the puzzle.  You will
  1594. Xalso be able to cheat and see the correct solution one letter at a time.
  1595. XA simple, yet entertaining example is the command:
  1596. X.sp
  1597. Xfortune -l | crypto -r
  1598. X.sp
  1599. Xwhich encrypts a long fortune with a simple roational cypher and lets you
  1600. Xsolve it.  For a more difficult time, try:
  1601. X.sp
  1602. Xfortune -s | crypto -e
  1603. X.PP
  1604. X.I Crypto
  1605. Xcan also be used in a non-interactive manner by redirecting the output to
  1606. Xa file.  In this case, the text is read in, encoded if -e, -r, or -c was
  1607. Xspecified, and the resulting
  1608. X.I puzzle
  1609. Xis output.  If, however, a guess was
  1610. Xspecified with the -g option, the guess is applied to the puzzle and the
  1611. Xresulting
  1612. X.I solution
  1613. Xis output.  When redirecting, you will probably want to use the -n option
  1614. Xto avoid outputting the brace-commands (see below).  For example:
  1615. X.sp
  1616. Xcrypto -n -gzyxwvutsrqponmlkjihgfedcba puzz >solved
  1617. X.PP
  1618. X.I Crypto
  1619. Xuses a simple, text-based output format to save the puzzle, guess, cypher,
  1620. Xand title in a file.  These take the form of "brace-commands", each on a line
  1621. Xof their own, interspersed into the puzzle text.  {-gabc...xyz} specifies
  1622. Xthe current guess, {-cabc...xyz} specifes the cypher, and {-tTitle} specifies
  1623. Xthe title.  Any or all of these may be ommitted to take on their default
  1624. Xvalues.  In addition, the command {-end} allows you to separate the file
  1625. Xinto multiple puzzles, just as if you'd specified multiple file names on
  1626. Xthe command-line.  Each puzzle has a unique guess, cypher, and title.
  1627. X.PP
  1628. XWhen multiple puzzles are loaded, you will be presented with a menu
  1629. Xof choices for your initial puzzle.  From there, the save command (^S)
  1630. Xsaves all the puzzles into a single file.  This menu can be visited at
  1631. Xany time with the menu command (^M).
  1632. X.PP
  1633. XHere is a complete list of the interactive commands available.  You can
  1634. Xget a summary of this list with the command
  1635. X.I crypto -i
  1636. Xor by typing '?' while running
  1637. X.I crypto\.
  1638. X.PP
  1639. X.TP 13
  1640. X.B <let1><let2>
  1641. Xguess the substitution cypher a letter at a time.  This is your primary
  1642. Xtool in solving the cryptogram.  Example:  xb
  1643. X.TP 13
  1644. X.B <let><space>
  1645. Xundefine <let>'s current guess.  <space> can be any non-letter.  This
  1646. Xlets you selectively remove your letters and try again.
  1647. X.TP 13
  1648. X.B ^U<let>
  1649. Xthe alternate way to Undefine a letter's current guess.
  1650. X.TP 13
  1651. X.B ^X
  1652. XUndefine ALL the guessed letters.  Good for starting afresh.
  1653. X.TP 13
  1654. X.B ^C
  1655. XCheat -- if I know the solution, I will correct one letter in the
  1656. Xpuzzle each time you decide to cheat.
  1657. X.TP 13
  1658. X.B ^S<file>
  1659. XSave the current puzzle, guess, and cypher information in a file.
  1660. XThis allows you to continue where ever you left off with
  1661. Xthe command crypto <file>
  1662. X.TP 13
  1663. X.B ^D
  1664. XDefine the current guess to be the solution.  Useful before a save
  1665. Xto define the cypher to save along with the puzzle (if not already
  1666. Xknown).
  1667. X.TP 13
  1668. X.B ^H
  1669. XHint -- select a word to perform a dictionary search on.  This is
  1670. Xuseful for solving unknown cyphers.  All the currently guessed
  1671. Xletters affect the matching of dictionary words into the cypher word.
  1672. XWhile in hint-mode, type '?' for a brief command summary.
  1673. X.TP 13
  1674. X.B ^N
  1675. Xgo to the Next puzzle in a multi-puzzle file.
  1676. X.TP 13
  1677. X.B ^P
  1678. Xgo to the Previous puzzle in a multi-puzzle file.
  1679. X.TP 13
  1680. X.B ^M
  1681. Xpresents a Menu of the current puzzles available for selection.
  1682. X.TP 13
  1683. X.B ^A
  1684. Xtoggle the Alpha display between the two different output modes.
  1685. X.TP 13
  1686. X.B ^T
  1687. Xenter a (new) Title for this puzzle.
  1688. X.TP 13
  1689. X.B ^Q, <Esc>
  1690. XQuit -- leave the program.  Confirms the exit request if we
  1691. Xbelieve you might like to save the puzzle(s) first.
  1692. X.TP 13
  1693. X.B ^L, ^R
  1694. XRedraw the screen.
  1695. X.TP 13
  1696. X.B  6,  4
  1697. XMove a wide cryptogram left/right by 4 chars.
  1698. X.TP 13
  1699. X.B  2,  8
  1700. XMove a long cryptogram up/down by 2 lines.
  1701. X.TP 13
  1702. X.B  7,  1
  1703. XMove to the far left/right of a wide puzzle.
  1704. X.TP 13
  1705. X.B  9,  3
  1706. XMove to the top/bottom of a long puzzle.
  1707. X.PP
  1708. XThe following are valid command-line options:
  1709. X.TP 8
  1710. X.B \-u
  1711. XForce all input to Upper-case.
  1712. X.TP 8
  1713. X.B \-e
  1714. XEncode the input stream with a random cypher.
  1715. X.TP 8
  1716. X.B \-r
  1717. Xencode using a simpler, rot-based random cypher.  You can specify a specific
  1718. Xrotation by including a number from 1 to 26 after the r, as in:  -r13.
  1719. X.TP 8
  1720. X.B \-cSTR
  1721. Xencode using the Cypher STR for encryption.  STR is the 26 letters of the
  1722. Xalphabet in whatever order you choose.
  1723. X.TP 8
  1724. X.B \-gSTR
  1725. Xinitialize the Guessed letters to STR.
  1726. X.TP 8
  1727. X.B \-n
  1728. Xindicates that No brace-commands are to be included in the save or pipe
  1729. Xoutput.  Brace-commands are normally output to indicate the current
  1730. Xcypher, guess, and/or title.
  1731. X.TP 8
  1732. X.B FILE
  1733. Xread input from one or more FILEs, instead of stdin.
  1734. X.TP 8
  1735. X.B \-i
  1736. Xoutput a summary of the Interactive commands.
  1737. X.TP 8
  1738. X.B \-h
  1739. Xoutput a summary of the command-line options.
  1740. X.TP 8
  1741. X.B \-
  1742. Xthe null option can be used to avoid an empty command tail, which
  1743. Xwould output a short command-line summary.
  1744. X.SH FILES
  1745. X/usr/dict/words
  1746. X.SH AUTHOR
  1747. X.I Crypto
  1748. Xwas written by Wayne Davison.  Special thanx go to Bruce Holloway, whose
  1749. X"figure" program provided inspiration into curses & the dictionary lookup.
  1750. END_OF_FILE
  1751. if test 5709 -ne `wc -c <'crypto.man'`; then
  1752.     echo shar: \"'crypto.man'\" unpacked with wrong size!
  1753. fi
  1754. # end of 'crypto.man'
  1755. fi
  1756. if test -f 'puzzles' -a "${1}" != "-c" ; then 
  1757.   echo shar: Will not clobber existing file \"'puzzles'\"
  1758. else
  1759. echo shar: Extracting \"'puzzles'\" \(2802 characters\)
  1760. sed "s/^X//" >'puzzles' <<'END_OF_FILE'
  1761. X{-tThe Ring of Truth}
  1762. X        "B xcmmis evcw srv obveh nvssvep," pcbw Oeiwi bm c dlctvebmj
  1763. Xtibxv.
  1764. X        "Mi," Pcbw Jcmwcno, "yls B xcm.  Srv nvssvep cev Vntbpr, io
  1765. Xxilepv, io cm cmxbvms kiwv, yls srv ncmjlcjv bp srcs io Kiewie, zrbxr
  1766. XB zbnn mis lssve rvev.  Srvh cev nbmvp io c tvepv nimj umizm bm
  1767. XVntvm-niev:
  1768. X
  1769. X        "Srbp Ebmj, mi isrve, bp kcwv yh srv vntvp,
  1770. X        Zri'w gczm srvbe izm kisrve si jecy bs srvkpvntvp.
  1771. X        Elnve io xevvgve, kiescn, cmw pxcnnig,
  1772. X        Srbp bp c pnvvgve srcs gcxup dlbsv c zcnnig.
  1773. X        Srv Gizve cnkbjrsh evpsp bm srbp Nimv Ebmj.
  1774. X        Srv Gizve, cnebjrsh, oie wibmj hile Izm Srbmj.
  1775. X        Bo yeiuvm ie ylpsvw, bs xcmmis yv evkcwv.
  1776. X        Bo oilmw, pvmw si Piervw (zbsr gipscjv gevgcbw)."
  1777. X{-ccyxwvojrbaunkmigdepsltzfhq}
  1778. X{-end}
  1779. X{-tSign of the Times}
  1780. X        PGMVODM (Mgb 23 - Wmx 21)
  1781. XHmu qvy pcvyrf dw lupdwypp qwf gqwwmb ly bvupbyf.  Hmu rdjj qgcdyxy bcy
  1782. Xodwwqgjy mz puggypp lygqupy mz hmuv bmbqj jqgt mz ybcdgp.  Kmpb Pgmvodm
  1783. Xoymojy qvy kuvfyvyf.
  1784. X{-cqlgfyzecditjkwmosvpbuxrnha}
  1785. X{-end}
  1786. X{-tOver Exposure}
  1787. XQgu Qgpib Ons vx Wgvqvlinwgt:
  1788. X        Px tva bpb ynrnlu qv luq nrt lvvb hgvqh, qgut spoo cu iaprub
  1789. X        sgur hvyuvru prnbkuiqurqot vwurh qgu bnijivvy bvvi nrb noo vx
  1790. X        qgu bnij ounjh vaq.
  1791. X{-cncdbuxlgpmjoyrvwfihqaksetz}
  1792. X{-end}
  1793. X{-tIlluminating Questions}
  1794. XDmq zenf deucqeua antonaaup cmap ob beha bm sdenta e votdbiyvi?
  1795. XNmna: "Qa'vv goj ob on pmgbqeua."
  1796. X
  1797. XDmq zenf pmgbqeua antonaaup cmap ob beha bm sdenta e votdbiyvi?
  1798. XNmna: "Qa'vv cmsyzanb ob on bda zenyev."
  1799. X
  1800. XDmq zenf basd quobaup cmap ob beha bm sdenta e votdbiyvi?
  1801. XNmna: "Bda ypau sen qmuh ob myb."
  1802. X{-ceiscagtdorhvznmwlupbyxqjfk}
  1803. X{-end}
  1804. X{-tSearch for Knowledge}
  1805. XUzmqm bc v uzmoqh szbxz cuvumc uzvu bl mpmq vrhorm wbcxopmqc mdvxukh
  1806. Xszvu uzm Nrbpmqcm bc loq vrw szh bu bc zmqm, bu sbkk brcuvrukh
  1807. Xwbcvaamvq vrw gm qmakvxmw gh cojmuzbrf mpmr joqm gbyvqqm vrw
  1808. Xbrmdakbxvgkm.  Uzmqm bc vrouzmq uzmoqh szbxz cuvumc uzvu uzbc zvc
  1809. Xvkqmvwh zvaamrmw.
  1810. X                -- Uzm Zbuxzzbtmq'c Fnbwm uo uzm Fvkvdh
  1811. X{-cvgxwmlfzbetkjroaiqcunpsdhy}
  1812. X{-end}
  1813. X{-tFowl Whether}
  1814. XKgfyzytl-Kfddcytl, wx ytzjr sla,
  1815. XDsl tzxd luud ca qsl Gltzqcbl Vsla.
  1816. XDsl eflda'q tzx luud ca qsl Kfdcqcbl Afv
  1817. XYljzidl dsl'd iazytl qf kfdqitzql sfv.
  1818. X                -- Hglelgcjr Vcadfg
  1819. X{-czyjelhuscprtwafkogdqibvnxm}
  1820. X{-end}
  1821. X{-tAxiom of the Week}
  1822. XTohbh rw dz trch grfh toh ybhwhdt nzb yzwtyzdrdk xoet szj zjkot tz uh
  1823. Xqzrdk.
  1824. X{-ceumqhnkorpfgcdzyabwtjlxvsi}
  1825. X{-end}
  1826. X{-tPessimistic Pragma}
  1827. XCmnfay't dmtuwnzui:
  1828. X        Fh lmw'ei hiinfay ymmo, oma'u qmeel.  Lmw'nn yiu mxie fu.
  1829. X{-czcroihygfvpnkamdsetuwxqblj}
  1830. X{-end}
  1831. X{-tDefinition}
  1832. XMxvsyshz: Rsvygozj gy yuz yxm xl xjz'v hxsqz.
  1833. X{-cgfqkzlpuscobrjxmewvythdani}
  1834. X{-end}
  1835. X{-tDefinition II}
  1836. XRbtjyjvhpu: R ejbi-ncuupuw muchlpu tcrt ibqf bg chppf rqw wjnq guwuftihrqf.
  1837. X{-crvlwueachzxpyqjgkiftbmndso}
  1838. X{-end}
  1839. END_OF_FILE
  1840. if test 2802 -ne `wc -c <'puzzles'`; then
  1841.     echo shar: \"'puzzles'\" unpacked with wrong size!
  1842. fi
  1843. # end of 'puzzles'
  1844. fi
  1845. echo shar: End of shell archive.
  1846. exit 0
  1847.